/**
 * @file CartBean.java
 * Projet eCOM 2010 (Miage Descartes)
 * @author Doido Sébastien
 * @version 2
 * @brief Bean relatif au traitement du panier d'achat client
 */
package ecom.beans;

import java.util.Collection;
import java.util.LinkedList;
import javax.ejb.Local;
import javax.ejb.Stateful;

/**
 * @brief Bean relatif au traitement du panier d'achat client
 * @author Sebastien
 */
@Stateful
@Local(CartLocal.class)
public class CartBean implements CartLocal {

    /**
     * @brief Etat du panier
     */
    public enum CartState {

        EMPTY,
        FILLING,
        BOUGHT
    };

    /**
     * @brief représente les lignes de commande (stock / quantité)
     */
    private Collection<CartLine> orders;

    /**
     * @brief représente l'état du panier
     */
    private CartState state;

    /**
     * @brief représente le montant total du panier
     */
    private double totalPrice;

    public CartBean() {
        super();
        orders = new LinkedList<CartLine>();
        this.totalPrice = 0;
        this.state = CartState.EMPTY;
    }

    /**
     * @brief renvoie les lignes de commande
     * @return les lignes de commande
     */
    public Collection<CartLine> getProducts() {
        return orders;
    }

    /**
     * @brief renvoie l'état du panier
     * @return l'état du panier
     */
    public CartState getState() {
        return state;
    }

    /**
     * @brief renvoie le montant total du panier
     * @return le montant total du panier
     */
    public double getTotalPrice() {
        return totalPrice;
    }

    /**
     * @brief définit l'état du panier
     * @param state : nouvel état
     */
    public void setState(CartState state) {
        this.state = state;
    }

    /**
     * @brief Définit le montant total du panier
     * @param totalPrice : nouveau montant
     */
    public void setTotalPrice(double totalPrice) {
        this.totalPrice = totalPrice;
    }

    /**
     * @brief Ajoute un produit dans le panier
     * @param stock : ligne de stock inventaire
     * @param quantity : quantité désirée
     * @throws ecom.beans.CartException : Erreur (panier acheté)
     */
    @Override
    public void addProduct(WarehouseLineBean stock, int quantity) throws CartException {
        if (getState() == CartState.BOUGHT) {
            throw new CartException("Cart already bought. Impossible to add Product #" + stock.getProduct().getProductId());
        } else {
            if (getState() == CartState.EMPTY) {
                this.setState(CartState.FILLING);
            }
            CartLine l = this.findLine(stock);
            if (l != null) {
                l.setOrderedQuantity(l.getOrderedQuantity() + quantity);
            } else {
                this.getProducts().add(new CartLine(stock, quantity));
            }
            //stock.setQuantity(stock.getQuantity() - quantity); // Stock update (=lock)
            this.setTotalPrice(this.getTotalPrice() + (stock.getProductPrice() * quantity));
        }
    }

    /**
     * @brief Retire un produit du panier
     * @param stock : ligne de stock inventaire
     * @param quantity : quantité à retirer
     * @throws ecom.beans.CartException : Erreur (erreur quantité)
     */
    public void removeProduct(WarehouseLineBean stock, int quantity) throws CartException {
        CartLine found = this.findLine(stock);
        if (found != null) {
            if (quantity > found.getOrderedQuantity()) {
                throw new CartException("\t Impossible to remove '" + quantity + "' product #" + stock.getProduct().getProductId() + " for Store #" + stock.getStore().getReference() + " (max removable : " + found.getOrderedQuantity() + ")");
            } else if (found.getOrderedQuantity() == quantity) {
                this.getProducts().remove(found);
            } else {
                found.setOrderedQuantity(found.getOrderedQuantity() - quantity);
            }
            //stock.setQuantity(stock.getQuantity() + quantity);
            this.setTotalPrice(this.getTotalPrice() - (stock.getProductPrice() * quantity));

            if (this.getProducts().size() == 0) {
                this.setState(CartState.EMPTY);
            }
        } else {
            throw new CartException("\t /!\\ Product #" + stock.getProduct().getProductId() + " | Store #" + stock.getStore().getReference() + " not in cart");
        }

    }

    /**
     * @brief Achat du contenu du panier par un client
     * @param customer : client
     * @throws ecom.beans.CartException : erreur (panier vide, solde insuffisant...)
     * @return montant total du panier
     */
    @Override
    public double buy(AccountBean customer) throws CartException {
        double total = this.getTotalPrice();
        if (this.getProducts().isEmpty()) {
            throw new CartException("Empty Cart");
        } else {
            if (customer.getBalance() >= this.getTotalPrice()) {

                for (CartLine line : this.getProducts()) {
                    // stock update
                    WarehouseLineBean stock = line.getStock();
                    System.out.println("old q before buy : " + stock.getQuantity());
                    //stock.setQuantity(stock.getQuantity() - line.getOrderedQuantity());
                    line.setStock(stock);
                    System.out.println("new q after buy : " + (stock.getQuantity() - line.getOrderedQuantity()));


                    // store account update
                    ProductStoreBean store = stock.getStore();
                    AccountBean storeAccount = store.getAccount();
                    storeAccount.deposit(stock.getProductPrice() * line.getOrderedQuantity());
                    store.setAccount(storeAccount);
                }
                // customer account update
                customer.withdraw(this.getTotalPrice());

                this.setState(CartState.BOUGHT);
                //emptyCart();
            } else {
                throw new CartException("Insufficient funds");
            }
        }
        return total;
    }

    @Override
    public String toString() {
        return "Caddie - Nb articles : " + orders.size() + " - total = " + this.getTotalPrice();
    }

    /**
     * @brief Renvoie la ligne de commande du panier pour une ligne de stock demandée
     * @param stock : ligne d'inventaire à rechercher dans le panier
     * @return une ligne de commande
     */
    private CartLine findLine(WarehouseLineBean stock) {
        for (CartLine l : this.getProducts()) {
            if (l.getStock().getProduct().getProductId() == stock.getProduct().getProductId() &&
                    l.getStock().getStore().getReference() == stock.getStore().getReference()) {
                return l;
            }
        }
        return null;
    }

    /**
     * @brief Réinitialise le panier
     */
    public void emptyCart() {
        this.getProducts().clear();
        this.setTotalPrice(0.0);
        this.setState(CartState.EMPTY);
    }
}
